/**
 * @file modbus_slave_simulator.cpp
 * @brief Modbus RTU 从站模拟器
 *
 * 模拟多个PM2220电表，用于测试DeviceManager
 * 支持虚拟串口对测试
 */

#include <QCoreApplication>
#include <QSerialPort>
#include <QTimer>
#include <QThread>
#include <QDebug>
#include <QDateTime>
#include <QVector>
#include <QMap>
#include <random>

/**
 * @brief 模拟电表类
 */
class SimulatedMeter
{
public:
    SimulatedMeter(int id) : m_id(id)
    {
        // 初始化随机数据
        m_ua = 220.0 + (rand() % 20 - 10); // 210-230V
        m_ub = 220.0 + (rand() % 20 - 10);
        m_uc = 220.0 + (rand() % 20 - 10);
        m_ia = 10.0 + (rand() % 100) / 10.0; // 10-20A
        m_ib = 10.0 + (rand() % 100) / 10.0;
        m_ic = 10.0 + (rand() % 100) / 10.0;
    }

    int id() const { return m_id; }

    // 获取寄存器数据
    QVector<quint16> getRegisters()
    {
        // 模拟数据微小变化
        m_ua += (rand() % 10 - 5) * 0.1;
        m_ub += (rand() % 10 - 5) * 0.1;
        m_uc += (rand() % 10 - 5) * 0.1;
        m_ia += (rand() % 10 - 5) * 0.01;
        m_ib += (rand() % 10 - 5) * 0.01;
        m_ic += (rand() % 10 - 5) * 0.01;

        // 限制范围
        m_ua = qBound(200.0, m_ua, 240.0);
        m_ub = qBound(200.0, m_ub, 240.0);
        m_uc = qBound(200.0, m_uc, 240.0);
        m_ia = qBound(5.0, m_ia, 25.0);
        m_ib = qBound(5.0, m_ib, 25.0);
        m_ic = qBound(5.0, m_ic, 25.0);

        QVector<quint16> registers;
        registers.append(static_cast<quint16>(m_ua * 10));   // 0x0000
        registers.append(static_cast<quint16>(m_ub * 10));   // 0x0002
        registers.append(static_cast<quint16>(m_uc * 10));   // 0x0004
        registers.append(static_cast<quint16>(m_ia * 1000)); // 0x0006
        registers.append(static_cast<quint16>(m_ib * 1000)); // 0x0008
        registers.append(static_cast<quint16>(m_ic * 1000)); // 0x000A
        return registers;
    }

private:
    int m_id;
    double m_ua, m_ub, m_uc;
    double m_ia, m_ib, m_ic;
};

/**
 * @brief Modbus从站模拟器
 */
class ModbusSlaveSimulator : public QObject
{
    Q_OBJECT

public:
    explicit ModbusSlaveSimulator(const QString &portName, const QVector<int> &slaveIds, QObject *parent = nullptr)
        : QObject(parent), m_portName(portName)
    {
        // 创建模拟电表
        for (int id : slaveIds)
        {
            m_meters[id] = new SimulatedMeter(id);
        }

        // 打开串口
        m_serialPort = new QSerialPort(this);
        m_serialPort->setPortName(portName);
        m_serialPort->setBaudRate(115200);
        m_serialPort->setDataBits(QSerialPort::Data8);
        m_serialPort->setParity(QSerialPort::NoParity);
        m_serialPort->setStopBits(QSerialPort::OneStop);
        m_serialPort->setFlowControl(QSerialPort::NoFlowControl);

        if (!m_serialPort->open(QIODevice::ReadWrite))
        {
            qCritical() << "模拟器: 无法打开串口" << portName << ":" << m_serialPort->errorString();
            return;
        }

        qInfo() << QString("模拟器: ✓ 已启动 [%1], 模拟站号: %2-%3，共 %4 台设备")
                       .arg(portName)
                       .arg(slaveIds.first())
                       .arg(slaveIds.last())
                       .arg(slaveIds.size());

        // 连接数据接收信号
        connect(m_serialPort, &QSerialPort::readyRead, this, &ModbusSlaveSimulator::onDataReceived);
    }

    ~ModbusSlaveSimulator()
    {
        if (m_serialPort && m_serialPort->isOpen())
        {
            m_serialPort->close();
        }
        qDeleteAll(m_meters);
        qInfo() << "模拟器: 已停止 [" << m_portName << "]";
    }

private slots:
    void onDataReceived()
    {
        QByteArray newData = m_serialPort->readAll();
        m_buffer.append(newData);

        qDebug() << QString("模拟器 [%1]: 接收到 %2 字节数据，缓冲区: %3 字节")
                        .arg(m_portName)
                        .arg(newData.size())
                        .arg(m_buffer.size());

        // 检查是否有完整的Modbus请求（至少8字节）
        while (m_buffer.size() >= 8)
        {
            // 尝试解析请求
            if (processRequest())
            {
                // 成功处理，继续检查缓冲区
                continue;
            }
            else
            {
                // 不是有效请求，丢弃第一个字节
                qDebug() << QString("模拟器 [%1]: 丢弃无效字节: 0x%2")
                                .arg(m_portName)
                                .arg(static_cast<quint8>(m_buffer[0]), 2, 16, QChar('0'));
                m_buffer.remove(0, 1);
            }
        }
    }

private:
    bool processRequest()
    {
        if (m_buffer.size() < 8)
            return false;

        quint8 slaveId = static_cast<quint8>(m_buffer[0]);
        quint8 functionCode = static_cast<quint8>(m_buffer[1]);

        // 验证CRC
        QByteArray request = m_buffer.left(8);
        if (!verifyCRC(request))
        {
            return false;
        }

        // 检查是否是我们模拟的站号
        if (!m_meters.contains(slaveId))
        {
            qDebug() << QString("模拟器 [%1]: 站号 %2 不在本总线，忽略")
                            .arg(m_portName)
                            .arg(slaveId);
            m_buffer.remove(0, 8);
            return true; // 不是我们的站号，忽略
        }

        // 只处理0x03功能码（读保持寄存器）
        if (functionCode != 0x03)
        {
            m_buffer.remove(0, 8);
            return true;
        }

        // 解析寄存器地址和数量
        quint16 startAddress = (static_cast<quint8>(m_buffer[2]) << 8) | static_cast<quint8>(m_buffer[3]);
        quint16 quantity = (static_cast<quint8>(m_buffer[4]) << 8) | static_cast<quint8>(m_buffer[5]);

        // 生成响应
        QByteArray response;
        response.append(static_cast<char>(slaveId));
        response.append(static_cast<char>(functionCode));
        response.append(static_cast<char>(quantity * 2)); // 字节数

        // 获取寄存器数据
        SimulatedMeter *meter = m_meters[slaveId];
        QVector<quint16> registers = meter->getRegisters();

        // 添加寄存器数据
        for (quint16 reg : registers)
        {
            response.append(static_cast<char>(reg >> 8));   // 高字节
            response.append(static_cast<char>(reg & 0xFF)); // 低字节
        }

        // 添加CRC
        quint16 crc = calculateCRC(response);
        response.append(static_cast<char>(crc & 0xFF));        // CRC低字节
        response.append(static_cast<char>((crc >> 8) & 0xFF)); // CRC高字节

        // 模拟实际电表的响应延迟（10-30ms）
        QThread::msleep(10 + (rand() % 20));

        // 发送响应
        qint64 bytesWritten = m_serialPort->write(response);
        m_serialPort->flush();

        if (bytesWritten != response.size())
        {
            qWarning() << QString("模拟器 [%1]: 站号 %2 响应发送不完整: %3/%4 字节")
                              .arg(m_portName)
                              .arg(slaveId)
                              .arg(bytesWritten)
                              .arg(response.size());
        }
        else
        {
            qDebug() << QString("模拟器 [%1]: ✓ 响应站号 %2, Ua=%3V, Ia=%4A (%5字节)")
                            .arg(m_portName)
                            .arg(slaveId)
                            .arg(registers[0] * 0.1, 0, 'f', 1)
                            .arg(registers[3] * 0.001, 0, 'f', 3)
                            .arg(bytesWritten);
        }

        // 移除已处理的请求
        m_buffer.remove(0, 8);
        return true;
    }

    quint16 calculateCRC(const QByteArray &data)
    {
        quint16 crc = 0xFFFF;
        for (int i = 0; i < data.size(); ++i)
        {
            crc ^= static_cast<quint8>(data[i]);
            for (int j = 0; j < 8; ++j)
            {
                if (crc & 0x0001)
                {
                    crc >>= 1;
                    crc ^= 0xA001;
                }
                else
                {
                    crc >>= 1;
                }
            }
        }
        return crc;
    }

    bool verifyCRC(const QByteArray &data)
    {
        if (data.size() < 3)
            return false;

        QByteArray payload = data.left(data.size() - 2);
        quint16 receivedCRC = (static_cast<quint8>(data[data.size() - 1]) << 8) |
                              static_cast<quint8>(data[data.size() - 2]);
        quint16 calculatedCRC = calculateCRC(payload);

        bool valid = (receivedCRC == calculatedCRC);
        if (!valid)
        {
            qDebug() << QString("模拟器 [%1]: CRC校验失败 - 接收: 0x%2, 计算: 0x%3")
                            .arg(m_portName)
                            .arg(receivedCRC, 4, 16, QChar('0'))
                            .arg(calculatedCRC, 4, 16, QChar('0'));
        }

        return valid;
    }

private:
    QString m_portName;
    QSerialPort *m_serialPort;
    QMap<int, SimulatedMeter *> m_meters;
    QByteArray m_buffer;
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    qInfo() << "========================================";
    qInfo() << "   Modbus RTU 从站模拟器 v1.1";
    qInfo() << "========================================";
    qInfo() << "";
    qInfo() << "虚拟串口配置:";
    qInfo() << "  COM1 ↔ COM2  (总线1: 配电室A)";
    qInfo() << "  COM3 ↔ COM4  (总线2: 配电室B)";
    qInfo() << "  COM5 ↔ COM6  (总线3: 配电室C)";
    qInfo() << "";
    qInfo() << "主站应连接: COM1, COM3, COM5";
    qInfo() << "模拟器监听: COM2, COM4, COM6";
    qInfo() << "波特率: 115200 bps";
    qInfo() << "";

    // 创建3个模拟器，分别监听COM2, COM4, COM6
    // 模拟完整的120块电表（每条总线40块）

    // 总线1：配电室A，站号1-40
    QVector<int> bus1Slaves;
    for (int i = 1; i <= 40; ++i)
        bus1Slaves.append(i);
    ModbusSlaveSimulator *sim1 = new ModbusSlaveSimulator("COM2", bus1Slaves, &app);

    // 总线2：配电室B，站号41-80
    QVector<int> bus2Slaves;
    for (int i = 41; i <= 80; ++i)
        bus2Slaves.append(i);
    ModbusSlaveSimulator *sim2 = new ModbusSlaveSimulator("COM4", bus2Slaves, &app);

    // 总线3：配电室C，站号81-120
    QVector<int> bus3Slaves;
    for (int i = 81; i <= 120; ++i)
        bus3Slaves.append(i);
    ModbusSlaveSimulator *sim3 = new ModbusSlaveSimulator("COM6", bus3Slaves, &app);

    qInfo() << "";
    qInfo() << "========================================";
    qInfo() << "  ✓ 所有模拟器已就绪 (共120台设备)";
    qInfo() << "  ✓ 等待主站连接...";
    qInfo() << "  ✓ 按 Ctrl+C 停止";
    qInfo() << "========================================";
    qInfo() << "";

    int result = app.exec();

    qInfo() << "";
    qInfo() << "模拟器已停止";

    return result;
}

#include "modbus_slave_simulator.moc"
